package com.brian.proxy.proxy;

import com.brian.proxy.service.OrderService;
import com.brian.proxy.service.impl.BrianJdkInvocationhandler;
import com.brian.proxy.service.impl.JavaClassLoader;
import com.brian.proxy.service.impl.OrderServiceImpl;

import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @program: architect
 * @author: Brian Huang
 * @create: 2019-05-20 22
 **/
public class MyProxy {

    static String rt = "\r\t";

    /**
     * @param classInfo 被代理实现的接口信息 <br>
     * @param h
     * @return
     */
    public static Object newProxyInstance(JavaClassLoader javaClassLoader, Class classInfo, BrianJdkInvocationhandler h) {
        try {
            // 1.创建代理类java源码文件,写入到硬盘中..
            Method[] methods = classInfo.getMethods();
            String proxyClass = "package com.brian.proxy.service.impl;" + rt
                    + "import java.lang.reflect.Method;" + rt
                    + "import com.brian.proxy.service.impl.BrianJdkInvocationhandler;" + rt
                    + "import java.lang.reflect.InvocationTargetException;" + rt
                    + "public class $Proxy2 implements " + classInfo.getName() + "{" + rt
                    + "BrianJdkInvocationhandler h;" + rt
                    + "public $Proxy2(BrianJdkInvocationhandler h)" + "{" + rt
                    + "this.h= h;" + rt + "}"
                    + getMethodString(methods, classInfo) + rt + "}";
            // 2. 将代理类源码文件写入硬盘中
            //String filename = "C:\\Users\\LiangHuang\\Desktopd\\$Proxy2.java";
            String filename = JavaClassLoader.class.getResource("").getPath()+"$Proxy2.java";
            File f = new File(filename);
            FileWriter fw = new FileWriter(f);
            fw.write(proxyClass);
            fw.flush();
            fw.close();

            // 3.使用JavaCompiler 编译该$Proxy2源代码 获取class文件
            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
            StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null);
            Iterable units = fileMgr.getJavaFileObjects(filename);
            JavaCompiler.CompilationTask t = compiler.getTask(null, fileMgr, null, null, null, units);
            t.call();
            fileMgr.close();

            //4.使用classClassLoader 将$Proxy2.class读取到内存中...
            Class proxy2Class = javaClassLoader.findClass("$Proxy2");
            //5.使用java反射机制给函数中赋值
            Constructor m = proxy2Class.getConstructor(BrianJdkInvocationhandler.class);
            Object o = m.newInstance(h);
            return o;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    public static String getMethodString(Method[] methods, Class intf) {
        String proxyMe = "";
        for (Method method : methods) {
            proxyMe += "public void " + method.getName() + "() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {" + rt
                    + "Method md= " + intf.getName() + ".class.getMethod(\"" + method.getName()
                    + "\",new Class[]{});" + rt
                    + "this.h.invoke(this,md,null);" + rt + "}" + rt;

        }
        return proxyMe;
    }

    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        OrderService o =
                (OrderService) MyProxy.newProxyInstance(new JavaClassLoader(), OrderService.class, new BrianJdkInvocationhandler(new OrderServiceImpl()));
        o.order();
    }

}
